package com.xbongbong.paas.service.workflow.setting.impl;

import com.alibaba.fastjson.JSON;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.config.enums.WorkflowTriggerMethodEnum;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.help.WorkflowNodeHelp;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.workflow.NodeCoreConfigurationPojo;
import com.xbongbong.paas.pojo.workflow.WorkflowNodeTreePojo;
import com.xbongbong.paas.pojo.workflow.nodes.vo.UpdateRecordNodeVO;
import com.xbongbong.paas.pojo.workflow.nodes.vo.WorkflowNodeGetVO;
import com.xbongbong.paas.pojo.workflow.settings.WorkflowGetPojo;
import com.xbongbong.paas.pojo.workflow.settings.vo.WorkflowEnableVO;
import com.xbongbong.paas.pojo.workflow.settings.vo.WorkflowOperationsVO;
import com.xbongbong.paas.service.workflow.setting.AbstractWorkflowNodeSettings;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.RegexUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.paas.util.WorkflowNodeUtil;
import com.xbongbong.paas.util.WorkflowUtil;
import com.xbongbong.pro.enums.errorcodes.ProErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.workflow.WorkflowValueTypeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.domain.entity.WorkOrderFormEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.model.WorkOrderFormModel;
import com.xbongbong.workflow.domain.entity.WorkflowNodeEntity;
import com.xbongbong.workflow.domain.entity.ext.WorkflowNodeEntityExt;
import com.xbongbong.workflow.enums.WorkflowNodeTypeEnum;
import com.xbongbong.workflow.pojo.WorkflowOperationsPojo;
import com.xbongbong.workflow.pojo.nodes.UpdateRecordNode;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author 吴峰
 * @date 2021/05/21 14:35
 */
@Service("workflowNodeUpdateSettings")
public class WorkflowNodeUpdateSettings extends AbstractWorkflowNodeSettings {
    private static String CONSTANT = "constant.workflowNode.update_data_node_content";

    private static final Logger LOGGER = LoggerFactory.getLogger(WorkflowNodeUpdateSettings.class);

    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private WorkOrderFormModel workOrderFormModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private WorkflowNodeHelp workflowNodeHelp;


    @Override
    public Integer type() {
        return WorkflowNodeTypeEnum.UPDATE_NODE.getType();
    }

    @Override
    public WorkflowNodeTreePojo getContent(WorkflowNodeEntity workflowNodeEntity, WorkflowGetPojo workflowGetPojo) throws XbbException{

        WorkflowNodeTreePojo workflowNodeTreePojo = new WorkflowNodeTreePojo();
        try {
            List<String> list = getNodeContent(workflowGetPojo, workflowNodeEntity, CONSTANT);
            workflowNodeTreePojo.setContent(list);
        } catch (Exception e) {
            LOGGER.error("WorkflowNodeUpdateSettings.getContent error", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return workflowNodeTreePojo;
    }

    @Override
    public WorkflowNodeGetVO get(WorkflowNodeEntity workflowNodeEntity) throws XbbException {
        try {
            UpdateRecordNode updateRecordNode = JSON.parseObject(workflowNodeEntity.getConfigData(), UpdateRecordNode.class);
            NodeCoreConfigurationPojo nodeCoreConfigurationPojo = new NodeCoreConfigurationPojo();
            UpdateRecordNodeVO updateRecordNodeVO = getUpdateRecordNode(updateRecordNode, workflowNodeEntity);

            nodeCoreConfigurationPojo.setUpdateRecordNode(updateRecordNodeVO);

            WorkflowNodeGetVO workflowNodeGetVO = new WorkflowNodeGetVO(workflowNodeEntity.getAppId(), workflowNodeEntity.getFormId(), workflowNodeEntity.getMenuId(), workflowNodeEntity.getSaasMark(), workflowNodeEntity.getBusinessType(),
                    workflowNodeEntity.getUid(), workflowNodeEntity.getId(), workflowNodeEntity.getPrevId(), workflowNodeEntity.getWrapperId(), nodeCoreConfigurationPojo);
            List<Integer> nodeTypeList = Arrays.asList(WorkflowNodeTypeEnum.START_NODE.getType(), WorkflowNodeTypeEnum.CREATE_NODE.getType(),
                    WorkflowNodeTypeEnum.SINGLE_DATA_NODE.getType(), WorkflowNodeTypeEnum.MULTI_DATA_NODE.getType());
            workflowNodeGetVO.setNodeList(getBeforeNodeListByNodeType(workflowNodeEntity.getCorpid(), workflowNodeEntity.getWorkflowId(), workflowNodeEntity.getId(), nodeTypeList));
            return workflowNodeGetVO;
        } catch (Exception e) {
            LOGGER.error("WorkflowNodeUpdateSettings.get error", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    private UpdateRecordNodeVO getUpdateRecordNode(UpdateRecordNode updateRecordNode, WorkflowNodeEntity workflowNodeEntity) throws XbbException {
        if (Objects.isNull(updateRecordNode) || updateRecordNode.getOperations() == null) {
            return null;
        }
        String corpid = workflowNodeEntity.getCorpid();
        Set<Long> workflowNodeIdSet = new HashSet<>();
        Set<Long> formIdSet = new HashSet<>();
        Set<Long> workOrderFormIdSet = new HashSet<>();
        Long workflowNodeId = updateRecordNode.getWorkflowNodeId();
        workflowNodeIdSet.add(workflowNodeId);
        Long formId = workflowNodeEntity.getFormId();
        Integer businessType = workflowNodeEntity.getBusinessType();
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)) {
            workOrderFormIdSet.add(formId);
        } else {
            formIdSet.add(formId);
        }

        getFormIdSet(updateRecordNode.getOperations(), formIdSet, workOrderFormIdSet, workflowNodeIdSet);

        Map<Long, WorkflowNodeEntity> workflowNodeEntityMap = getWorkflowNodeMap(workflowNodeIdSet, corpid);
        String nodeName = "";
        Integer delete = 1;
        if (workflowNodeEntityMap.containsKey(updateRecordNode.getWorkflowNodeId())) {
            nodeName = workflowNodeEntityMap.get(updateRecordNode.getWorkflowNodeId()).getName();
            delete = 0;
        }
        String formName = "";
        if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)) {
            WorkOrderFormEntity workOrderFormEntity = workOrderFormModel.getByKey(formId, corpid);
            if (Objects.nonNull(workOrderFormEntity)) {
                formName = workOrderFormEntity.getName();
            }
        } else {
           PaasFormEntity paasFormEntity = paasFormModel.getByKey(formId, corpid);
            if (Objects.nonNull(paasFormEntity)) {
                formName = paasFormEntity.getName();
            }
        }
        Map<Long, Map<String, FieldAttrEntity>> explainMap = proFormHelp.getFormFieldMap(formIdSet, corpid);
        Map<Long, Map<String, FieldAttrEntity>> workOrderExplainMap = proFormHelp.getWorkOrderFormFieldMap(workOrderFormIdSet, corpid);
        List<WorkflowOperationsVO> operations = getReturnOperationList(updateRecordNode.getOperations(), formId, businessType, explainMap, workOrderExplainMap, workflowNodeEntityMap);


        UpdateRecordNodeVO updateRecordNodeVO = new UpdateRecordNodeVO(updateRecordNode.getEditedData(), workflowNodeId, formId, workflowNodeEntity.getSaasMark(), businessType, nodeName, formName, delete,
                updateRecordNode.getTriggerNodeFlag(), updateRecordNode.getUpdateMethod(), operations);
        return updateRecordNodeVO;
    }



    @Override
    public WorkflowEnableVO check(WorkflowNodeEntity workflowNodeEntity, Map<Long, WorkflowNodeEntity> nodeMap, WorkflowGetPojo workflowGetPojo) throws XbbException {
        WorkflowEnableVO workflowEnableVO = new WorkflowEnableVO();
        UpdateRecordNode updateRecordNode = JSON.parseObject(workflowNodeEntity.getConfigData(), UpdateRecordNode.class);
        if (Objects.equals(workflowNodeEntity.getTriggerType(), WorkflowTriggerMethodEnum.FORM.getType())) {
            if (CollectionUtils.isEmpty(updateRecordNode.getOperations())) {
                workflowEnableVO.setSuccess(0);
                workflowEnableVO.setWorkflowNodeId(workflowNodeEntity.getId());
            } else {
                Long workflowNodeId = updateRecordNode.getWorkflowNodeId();
                WorkflowNodeEntity node = nodeMap.get(workflowNodeId);
                if (Objects.isNull(node)) {
                    // 节点被删除
                    return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260036.getMsg()));
                }
                if (!equals(workflowNodeEntity.getFormId(), workflowNodeEntity.getBusinessType(), node.getFormId(), node.getBusinessType())) {
                    // 表单被更改
                    return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260042.getMsg()));
                }
            }
            // 判断节点是否存在
            Long updateNodeId = updateRecordNode.getWorkflowNodeId();
            Map<Long, String> subFormMap = workflowNodeHelp.getSubForm(updateNodeId, workflowNodeEntity.getCorpid());
            String subFormAttr = workflowNodeHelp.getSubFormAttr(updateNodeId, workflowNodeEntity.getCorpid());
            for (WorkflowOperationsPojo item : updateRecordNode.getOperations()) {
                List<String> targetAttrList = ExplainUtil.getAttrByPoint(item.getAttr());
                if (Objects.equals(targetAttrList.size(), BasicConstant.TWO) && !Objects.equals(targetAttrList.get(0), subFormAttr)) {
                    return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260041.getMsg()));
                }
                if (Objects.equals(WorkflowValueTypeEnum.DYNAMIC_VALUE.getType(), item.getValueType())) {
                    if (!nodeMap.containsKey(item.getWorkflowNodeId())) {
                        // 节点被删除
                        return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260036.getMsg()));
                    }
                    targetAttrList = ExplainUtil.getAttrByPoint(item.getValueAttr());
                    String parentAttr = subFormMap.get(item.getWorkflowNodeId());
                    if (Objects.equals(targetAttrList.size(), BasicConstant.TWO) && !subFormMap.containsKey(item.getWorkflowNodeId())) {
                        //
                        return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260041.getMsg()));
                    } else if (Objects.equals(targetAttrList.size(), BasicConstant.TWO) && !Objects.equals(targetAttrList.get(0), parentAttr)) {
                        //
                        return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260041.getMsg()));
                    }
                    WorkflowNodeEntity node = nodeMap.get(item.getWorkflowNodeId());
                    if (!equals(item.getFormId(), item.getBusinessType(), node.getFormId(), node.getBusinessType())) {
                        // 节点被删除
                        return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260042.getMsg()));
                    }
                }else if (Objects.equals(WorkflowValueTypeEnum.FORMULA.getType(), item.getValueType())) {
                    String formula = item.getFormulaInfo().getFormula();
                    String[] formulaList = RegexUtil.getFormulaAttr(formula);
                    for (int i = 0; i < formulaList.length; i++) {
                        String formulaStr = formulaList[i];
                        String[] formulaArray = WorkflowUtil.getAttrByFormula(formulaStr);
                        if (formulaStr.contains(FieldTypeEnum.SUB_FORM.getEsalias())) {
                            // 1.节点id.目标表单id.subForm_1.text_1
                            // 1.节点id.workOrder_工单表单id.subForm_1.text_1
                           Long workflowNodeId = Long.valueOf(formulaArray[1]);
                           String formIdStr = formulaArray[2];
                           Long formId;
                           Integer businessType = null;
                           if (formIdStr.contains(XbbRefTypeEnum.WORK_ORDER.getAlias())) {
                               businessType = XbbRefTypeEnum.WORK_ORDER.getCode();
                               formId = Long.valueOf(formIdStr.replace(PaasConstant.WORK_ORDER, ""));
                           } else {
                               formId = Long.valueOf(formIdStr);
                               PaasFormEntity paasFormEntity = workflowGetPojo.getFormMap().get(formId);
                               if (Objects.nonNull(paasFormEntity)) {
                                   businessType = paasFormEntity.getBusinessType();
                               }
                           }
                           String subForm = formulaArray[3];
                            String parentAttr = subFormMap.get(workflowNodeId);
                            if ( !subFormMap.containsKey(workflowNodeId)) {
                                //
                                return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260041.getMsg()));
                            } else if (!Objects.equals(subForm, parentAttr)) {
                                //
                                return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260041.getMsg()));
                            }
                            WorkflowNodeEntity node = nodeMap.get(workflowNodeId);
                            if (!equals(formId, businessType, node.getFormId(), node.getBusinessType())) {
                                // 表单不一致
                                return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260042.getMsg()));
                            }
                        } else if (WorkflowUtil.validateFormula(formulaArray, formulaStr)) {
                            // 1.节点id.目标表单id.text_1
                            // 1.节点id.workOrder_工单表单id.text_1
                            Long workflowNodeId = Long.valueOf(formulaArray[1]);
                            String formIdStr = formulaArray[2];
                            Long formId;
                            Integer businessType = null;
                            if (formIdStr.contains(XbbRefTypeEnum.WORK_ORDER.getAlias())) {
                                businessType = XbbRefTypeEnum.WORK_ORDER.getCode();
                                formId = Long.valueOf(formIdStr.replace(PaasConstant.WORK_ORDER, ""));
                            } else {
                                formId = Long.valueOf(formIdStr);
                                PaasFormEntity paasFormEntity = workflowGetPojo.getFormMap().get(formId);
                                if (Objects.nonNull(paasFormEntity)) {
                                    businessType = paasFormEntity.getBusinessType();
                                }
                            }
                            if (!nodeMap.containsKey(workflowNodeId)) {
                                // 节点被删除
                                return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260036.getMsg()));
                            }
                            WorkflowNodeEntity node = nodeMap.get(workflowNodeId);
                            if (!equals(formId, businessType, node.getFormId(), node.getBusinessType())) {
                                // 表单不一致
                                return new WorkflowEnableVO(0, workflowNodeEntity.getId(), I18nMessageUtil.getMessage(ProErrorCodeEnum.API_ERROR_260042.getMsg()));
                            }
                        }
                    }
                }
            }
        }
        return workflowEnableVO;
    }


    @Override
    public void replaceWorkflowNodeId(WorkflowNodeEntityExt workflowNodeEntityExt, Map<Long, Long> workflowNodeMap) throws XbbException {
        UpdateRecordNode updateRecordNode = JSON.parseObject(workflowNodeEntityExt.getConfigData(), UpdateRecordNode.class);
        if (Objects.nonNull(updateRecordNode)) {
            if (Objects.nonNull(updateRecordNode.getWorkflowNodeId())) {
                updateRecordNode.setWorkflowNodeId(workflowNodeMap.get(updateRecordNode.getWorkflowNodeId()));
            }
            if (CollectionUtils.isNotEmpty(updateRecordNode.getOperations())) {
                WorkflowNodeUtil.replaceWorkflowNodeId(updateRecordNode.getOperations(), workflowNodeMap);
                workflowNodeEntityExt.setConfigData(JSON.toJSONString(updateRecordNode));
            }
        }
    }
}

